package com.sky.service.impl;

import com.github.pagehelper.Page;
import com.sky.dto.OrdersPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.Setmeal;
import com.sky.mapper.*;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.util.StringUtil;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 功能：
 * 作者：4204001140
 * 日期：2024/4/28 16:09
 */

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WorkspaceService workspaceService;
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private SetmealMapper setmealMapper;

    /**
     * 营业额统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {

        TurnoverReportVO turnoverReportVO = new TurnoverReportVO();

        // 1.获取时间段的字符串，每个时间以逗号分割，（因为前端的规定）
        // 1.1创建时间集合
        List<LocalDate> dateTimeList = new ArrayList<>();
        // 1.2每天的日期加入集合
        dateTimeList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            dateTimeList.add(begin);
        }
        // 1.3时间集合转为字符串，逗号分隔
        turnoverReportVO.setDateList(StringUtils.join(dateTimeList,","));

        // 2.遍历时间集合，获取每天的营业额
        List<Double> turnoverList = new ArrayList<>();

        for (LocalDate localDate : dateTimeList) {
            // 获取今天的首尾时间
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            Map map = new HashMap();
            map.put("beginTime", beginTime);
            map.put("endTime", endTime);
            map.put("status", Orders.COMPLETED);    // 筛选订单为 已完成
            // 获取今天的营业额
            Double turnover = orderMapper.sumByMap(map);
            turnover = turnover == null ? 0 : turnover;
            turnoverList.add(turnover)  ;
        }
        turnoverReportVO.setTurnoverList(StringUtils.join(turnoverList,","));
        return turnoverReportVO;
    }

    /**
     *  用户统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {

        UserReportVO userReportVO = new UserReportVO();

        // 1.获取时间段的字符串，每个时间以逗号分割，（因为前端的规定）
        // 1.1创建时间集合
        List<LocalDate> dateTimeList = new ArrayList<>();
        // 1.2每天的日期加入集合
        dateTimeList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            dateTimeList.add(begin);
        }
        // 1.3时间集合转为字符串，逗号分隔
        userReportVO.setDateList(StringUtils.join(dateTimeList,","));

        // 2.获取每个时间段的新用户数量和总用户量
        List<Integer> newUserList = new ArrayList<>();
        List<Integer> totalUserList = new ArrayList<>();

        for (LocalDate localDate : dateTimeList) {
            // 获取今天的首尾时间
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            Map map = new HashMap();
            map.put("endTime", endTime);
            // 获取到今天的总用户量
            Integer totalUser = userMapper.countByMap(map);
            totalUserList.add(totalUser);
            map.put("beginTime", beginTime);
            // 获取今天的新用户数量
            Integer newUser = userMapper.countByMap(map);
            newUserList.add(newUser);
        }
        userReportVO.setNewUserList(StringUtils.join(newUserList,","));
        userReportVO.setTotalUserList(StringUtils.join(totalUserList,","));
        return userReportVO;
    }

    /**
     * 订单统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        /**
         * ├─ dateList	string	必须		日期列表，以逗号分隔
         * ├─ orderCompletionRate	number	必须		订单完成率	            =  已完成订单/总订单数量
         * ├─ orderCountList	string	必须		订单数列表，以逗号分隔	        每天的订单数量
         * ├─ totalOrderCount	integer	必须		订单总数	                    迄今为止的订单总数量
         * ├─ validOrderCount	integer	必须		有效订单数	                迄今为止的有效订单总数量
         * ├─ validOrderCountList	string	必须		有效订单数列表，以逗号分隔	每天的有效订单数量       有效订单 = 订单的状态为已完成
         */
        OrderReportVO orderReportVO = new OrderReportVO();

        // 1.获取时间段的字符串，每个时间以逗号分割，（因为前端的规定）
        // 1.1创建时间集合
        List<LocalDate> dateTimeList = new ArrayList<>();
        // 1.2每天的日期加入集合
        dateTimeList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1);
            dateTimeList.add(begin);
        }
        // 1.3时间集合转为字符串，逗号分隔
        orderReportVO.setDateList(StringUtils.join(dateTimeList,","));

        // 每日订单数集合
        List<Integer> orderCountList = new ArrayList<>();
        // 每日有效订单数集合
        List<Integer> validOrderCountList = new ArrayList<>();

        for (LocalDate localDate : dateTimeList) {
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);

            // 2.获取该时间段的订单数量
            HashMap map = new HashMap();
            // 每日订单数量
            map.put("beginTime",beginTime);
            map.put("endTime",endTime);
            Integer orderCount = orderMapper.countByMap(map);
            orderCountList.add(orderCount);
            // 每日有效订单数量
            map.put("status",Orders.COMPLETED);
            Integer validOrderCount = orderMapper.countByMap(map);
            validOrderCountList.add(validOrderCount);
        }
        orderReportVO.setOrderCountList(StringUtils.join(orderCountList,","));
        orderReportVO.setValidOrderCountList(StringUtils.join(validOrderCountList,","));

        HashMap map = new HashMap();
        // 订单总数
        Integer totalOrderCount = orderMapper.countByMap(map);
        map.put("status",Orders.COMPLETED);
        // 订单有效数量
        Integer validOrderCount = orderMapper.countByMap(map);
        orderReportVO.setTotalOrderCount(totalOrderCount);
        orderReportVO.setValidOrderCount(validOrderCount);

        // 订单完成率
        double orderCompletionRate = 0;
        if (totalOrderCount != 0) {
            orderCompletionRate = (double) validOrderCount / totalOrderCount ;
        }
        orderReportVO.setOrderCompletionRate(orderCompletionRate);
        return orderReportVO;
    }

    /**
     * 查询销量排名top10
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {

        /**
         * ├─ nameList	string	必须		商品名称列表，以逗号分隔
         * ├─ numberList	string	必须		销量列表，以逗号分隔
         */


        // 1.时间范围内的订单数量
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        OrdersPageQueryDTO ordersPageQueryDTO = OrdersPageQueryDTO.builder()
                .beginTime(beginTime)
                .endTime(endTime)
                .build();
        Page<Orders> ordersPages = orderMapper.pageQuery(ordersPageQueryDTO);
        List<Orders> ordersList = ordersPages.getResult();

        // 统计订单内菜品或套餐的销量
        HashMap<String, Integer> result = new HashMap<>();

        for (Orders orders : ordersList) {
            // 获取该订单的菜品\套餐关系集合
            List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(orders.getId());
            // 累加该菜品\套餐的销量
            for (OrderDetail orderDetail : orderDetailList) {
                result.put(orderDetail.getName(), result.getOrDefault(orderDetail.getName(), 0) + orderDetail.getNumber());
            }
        }
        // 3.处理result这个map集合，进行排序截取销量前十的result,key是菜品名称，value是销量,使用流操作进行，返回一个nameList和一个numberList
        List<String> nameList = result.entrySet().stream()
                .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                .limit(10)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        List<Integer> numberList = result.entrySet().stream()
                .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                .limit(10)
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());

        return SalesTop10ReportVO
                .builder()
                .nameList(StringUtils.join(nameList, ","))
                .numberList(StringUtils.join(numberList, ","))
                .build();
    }

    /**
     * 导出Excel报表接口
     * @param response
     */
    @Override
    public void exportExcel(HttpServletResponse response) {
        // 1.获取导出的数据-- 本次获取的是近30天内的数据
        
        // 获取近三十天的时间间断
        LocalDate beginTime = LocalDate.now().minusDays(30);
        LocalDate endTime = LocalDate.now().minusDays(1);

        // 获取概括数据
        BusinessDataVO businessDataVO = workspaceService.getBusinessData(LocalDateTime.of(beginTime, LocalTime.MIN), LocalDateTime.of(endTime, LocalTime.MAX));

        // 2.将数据填入excel表中
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
        XSSFWorkbook excel = null;
        try {
            excel = new XSSFWorkbook(inputStream);
            XSSFSheet sheet = excel.getSheet("Sheet1");
            // 写入（1，1）时间
            sheet.getRow(1).getCell(1).setCellValue("时间：" + beginTime + " 至 " + endTime);
            // 获取第4行
            XSSFRow row = sheet.getRow(3);
            row.getCell(2).setCellValue(businessDataVO.getTurnover());                 // 写入营业额
            row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());      // 写入订单完成率
            row.getCell(6).setCellValue(businessDataVO.getNewUsers());                 // 写入新增用户数

            // 获取第5行
            row = sheet.getRow(4);
            row.getCell(2).setCellValue(businessDataVO.getValidOrderCount());           // 写入有效订单数量
            row.getCell(4).setCellValue(businessDataVO.getUnitPrice());                 // 写入平均客单价


            // 获取日期集合
            List<LocalDate> dateTimeList = new ArrayList<>();
            dateTimeList.add(beginTime);
            while (!beginTime.equals(endTime)){
                beginTime = beginTime.plusDays(1);
                dateTimeList.add(beginTime);
            }

            // 获取营业额、有效订单、订单完成率、 新增用户数、 平均客单价集合
            List<Double> turnoverList = new ArrayList<>();                  // 营业额
            List<Integer> newUserList = new ArrayList<>();                  // 新增用户数量
            List<Integer> orderCountList = new ArrayList<>();               // 今日订单数量
            List<Integer> validOrderCountList = new ArrayList<>();          // 有效订单数量
            List<Double> orderCompletionRateList = new ArrayList<>();       // 平均客单价

            int start = 7;

            for (LocalDate localDate : dateTimeList) {

                // 获取今天的首尾时间
                Map map = new HashMap();
                map.put("beginTime", LocalDateTime.of(localDate, LocalTime.MIN));
                map.put("endTime", LocalDateTime.of(localDate, LocalTime.MAX));

                // 每日订单数量
                Integer orderCount = orderMapper.countByMap(map);

                // 获取今天的新用户数量
                Integer newUser = userMapper.countByMap(map);

                map.put("status", Orders.COMPLETED);    // 筛选订单为 已完成
                // 获取今天的营业额
                Double turnover = orderMapper.sumByMap(map);
                turnover = turnover == null ? 0 : turnover;

                // 每日有效订单数量
                Integer validOrderCount = orderMapper.countByMap(map);

                // 平均客单价 = 营业额/有效订单数量
                Double avgPrice = validOrderCount == 0 ? 0 : turnover / validOrderCount;

                // 每日订单完成率 = 有效订单数量/每日订单数量
                Double completionRate = validOrderCount == 0 ? 0 : (double) validOrderCount / orderCount;


                 // 写入excel表格
                 row = sheet.getRow(start);

                 // 日期
                 row.getCell(1).setCellValue(localDate.toString());
                 // 营业额
                row.getCell(2).setCellValue(turnover);
                 //有效订单
                row.getCell(3).setCellValue(validOrderCount);
                //订单完成率
                row.getCell(4).setCellValue(completionRate);
                // 平均客单价
                row.getCell(5).setCellValue(avgPrice);
                // 新增用户数
                row.getCell(6).setCellValue(newUser);

                start +=1;
            }

            // 3.将生成的excel返回给浏览器
            ServletOutputStream outputStream = response.getOutputStream();
            excel.write(outputStream);


            // 4.关闭资源
            outputStream.close();
            inputStream.close();
            excel.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {

        }


    }
}
